﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace IcyTowerMobile
{
	/// <summary>
	/// Class representing a player animation.
	/// </summary>
	public class Animation
	{
		// Image representing the sprite sheet
		private Texture2D spriteStrip;

		// The scale used to display the sprite strip
		private float scale;

		// Time since the last update
		private int elapsedTime;

		// The time a frame is displayed until it changes
		private int frameTime;

		// The number of frames the spritesheet contains
		private int frameCount;

		// The index of the current frame
		private int currentFrame;

		// The color of the frame to be displayed
		private Color color;

		// The area of the image strip to be displayed
		private Rectangle sourceRect;

		// The area where where the image strip will be displayed in the game
		private Rectangle destinationRect;

		// The width of the frame Int FrameHeight
		private int frameWidth;

		// The height of the frame
		private int frameHeight;

		// The state of the animation
		private bool active;

		// Determines if the animation will keep playing or deactivate after one run
		private bool looping;

		// the origin of the animation
		private Vector2 origin;

		public int FrameWidth { get { return frameWidth; } }
		public int FrameHeight { get { return frameHeight; } }

		/// <summary>
		/// Initializes the animation with top-left origin.
		/// </summary>
		/// <param name="texture">Sprite sheet for the animation.</param>
		/// <param name="frameWidth">Width of a single sprite.</param>
		/// <param name="frameHeight">Height of sprite sheet.</param>
		/// <param name="frameCount">Number of sprites in sheet.</param>
		/// <param name="frametime">Duration in milliseconds one single sprite should be shown.</param>
		/// <param name="color">Background color of sprite.</param>
		/// <param name="scale">Scaling factor.</param>
		/// <param name="looping">True if the animation should start from scratch after finishing. False otherwise.</param>
		public void Initialize(Texture2D texture, int frameWidth, int frameHeight, int frameCount,
			int frametime, Color color, float scale, bool looping)
		{
			Initialize(texture, frameWidth, frameHeight, frameCount, frametime, color, scale, looping, false);
		}

		/// <summary>
		/// Initializes the animation.
		/// </summary>
		/// <param name="texture">Sprite sheet for the animation.</param>
		/// <param name="frameWidth">Width of a single sprite.</param>
		/// <param name="frameHeight">Height of sprite sheet.</param>
		/// <param name="frameCount">Number of sprites in sheet.</param>
		/// <param name="frametime">Duration in milliseconds one single sprite should be shown.</param>
		/// <param name="color">Background color of sprite.</param>
		/// <param name="scale">Scaling factor.</param>
		/// <param name="looping">True if the animation should start from scratch after finishing. False otherwise.</param>
		/// <param name="centerOrigin">True if the origin is centered. False if the origin is top-left.</param>
		public void Initialize(Texture2D texture, int frameWidth, int frameHeight, int frameCount,
			int frametime, Color color, float scale, bool looping, bool centerOrigin)
		{
			// keep a local copy of the values passed in
			this.spriteStrip = texture;
			this.frameWidth = frameWidth;
			this.frameHeight = frameHeight;
			this.frameCount = frameCount;
			this.frameTime = frametime;
			this.color = color;
			this.scale = scale;
			this.looping = looping;

			// set the time to zero
			elapsedTime = 0;
			currentFrame = 0;

			// set the animation to active by default
			active = true;

			if (centerOrigin)
			{
				// set origin to center
				origin = new Vector2(frameWidth / 2, frameHeight / 2);
			}
			else
			{
				// set origin to top-left
				origin = Vector2.Zero;
			}

		}

		/// <summary>
		/// Allows the game component to update itself.
		/// </summary>
		/// <param name="gameTime">Provides a snapshot of timing values.</param>
		public void Update(GameTime gameTime, Rectangle boundingbox)
		{
			// Do not update the game if we are not active
			if (!active) return;

			// Update the elapsed time
			elapsedTime += (int)gameTime.ElapsedGameTime.TotalMilliseconds;

			// If the elapsed time is larger than the frame time we need to switch frames
			if (elapsedTime > frameTime)
			{
				// Move to the next frame
				currentFrame++;

				// If the currentFrame is equal to frameCount reset currentFrame to zero
				if (currentFrame == frameCount)
				{
					currentFrame = 0;
					// If we are not looping deactivate the animation
					if (!looping) active = false;
				}
				// Reset the elapsed time to zero
				elapsedTime = 0;

			}

			// Grab the correct frame in the image strip by multiplying the currentFrame index by the frame width
			sourceRect = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
			destinationRect = new Rectangle(boundingbox.X, boundingbox.Y, frameWidth, frameHeight);
		}

		public void Draw(SpriteBatch spriteBatch, float rotation)
		{
			// Only draw the animation when we are active
			if (active)
			{
				spriteBatch.Draw(spriteStrip, destinationRect, sourceRect, color, rotation, origin, SpriteEffects.None, 0);
			}
		}
	}
}
